package gee

import (
	// "fmt"
	"net/http"
	"log"
	"strings"
	"path"
	"html/template"
)


type RouterGroup struct{
	prefix string
	middlewares []HandlerFunc
	parent  *RouterGroup
	engine  *Engine 
}


//定义请求的使用类型数据
type HandlerFunc func(*Context)
// type HandlerFunc func(http.ResponseWriter, *http.Request)

//定义结构体去实现原来的 ServerHTTP接口
type Engine struct{
    *RouterGroup
	router *router
    groups []*RouterGroup //store all groups
	// router map[string] HandlerFunc
	htmlTemplates *template.Template //for html render
	funcMap      template.FuncMap  //for html render
}

//构造函数 实现engine

func New() *Engine{

	engine := &Engine{router:newRouter()}
	engine.RouterGroup = &RouterGroup{engine:engine}
	engine.groups = []*RouterGroup{engine.RouterGroup}
	return engine
	//return &Engine{router:newRouter()}

}

//默认使用中间件
func Default() *Engine {
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}


//所有分组共享一个Engine 实例
func (group *RouterGroup) Group(prefix string) *RouterGroup{
	engine := group.engine
	newGroup :=&RouterGroup{
		prefix: group.prefix +prefix,
		parent:group,
		engine:engine,
	}
	engine.groups =append(engine.groups,newGroup)
	return newGroup
}

func (group *RouterGroup) addRoute(method string,comp string,handler HandlerFunc){
   pattern :=group.prefix + comp
   log.Printf("Route %4s-%s",method,pattern)
   group.engine.router.addRoute(method,pattern,handler)
	//engine.router.addRoute(method,pattern,handler)
}

//定义get 请求添加路由的方法
func (group *RouterGroup) GET(pattern string,handler HandlerFunc){
	group.addRoute("GET",pattern,handler)
	//engine.addRoute("GET",pattern,handler)
}

//定义添加POSt路由的方法

func (group *RouterGroup) POST(pattern string,handler HandlerFunc){
	group.addRoute("POST",pattern,handler)
	//engine.addRoute("POST",pattern,handler)
}


//定义启动http 服务的方法
func (engine *Engine) Run(addr string)(err error){
	return http.ListenAndServe(addr,engine)
}


func (engine *Engine)ServeHTTP(w http.ResponseWriter, req *http.Request){
	// key :=req.Method + "-" +req.URL.Path
	// if handler,ok :=engine.router[key];ok{
	// 	handler(w,req)
	// }else{
	// 	fmt.Fprintf(w,"404 NOT FOUND:%s\n",req.URL)
	// }
	var middlewares []HandlerFunc
	for _,group :=range engine.groups{
		if strings.HasPrefix(req.URL.Path,group.prefix){
			middlewares = append(middlewares,group.middlewares...)
		}
	}
	c :=newContext(w,req)
	c.handlers =middlewares
	c.engine = engine
	engine.router.handle(c)
}

func (group *RouterGroup) Use(middlewares ...HandlerFunc){
	group.middlewares =append(group.middlewares,middlewares...)
}


//create static handler

func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc{
	absolutePath :=path.Join(group.prefix,relativePath)
	fileServer := http.StripPrefix(absolutePath,http.FileServer(fs))
	return func(c *Context){
		file :=c.Param("filepath")
		// Check if file exists and/or if we have permission to access it
		if _,err :=fs.Open(file);err!=nil{
			c.Status(http.StatusNotFound)
			return 
		}
		fileServer.ServeHTTP(c.Writer,c.Req)
	}
}


func (group *RouterGroup) Static(relativePath string,root string){
	handler :=group.createStaticHandler(relativePath,http.Dir(root))

	urlPattern :=path.Join(relativePath,"/*filepath")
	// Register GET handlers
	group.GET(urlPattern,handler)
}

func (engine *Engine) SetFuncMap(funcMap template.FuncMap){
	engine.funcMap = funcMap
}

func (engine *Engine)LoadHTMLGlob(pattern string){
	engine.htmlTemplates = template.Must(template.New("").Funcs(engine.funcMap).ParseGlob(pattern))
}